﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
using DeliveryPlus.Web.Classes.Enums;
using DeliveryPlus.Web.Classes.Ext;
using DeliveryPlus.Web.Classes.Routing;
using DeliveryPlus.Web.DAL.Entities;
using Newtonsoft.Json.Linq;

namespace DeliveryPlus.Web.Controllers
{
    /// <summary>
    /// Главный контроллер системы
    /// </summary>
    public class MainController : BaseController
    {
        /// <summary>
        /// Главная страница сайта
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            ViewBag.news =
                DataContext.Articles.Where(a => a.PublicationDate <= DateTime.Now)
                    .OrderByDescending(a => a.PublicationDate).ThenByDescending(a => a.DateModified).ThenByDescending(f => f.DateCreated).Take(4)
                    .ToList();
            ViewBag.popular =
                DataContext.Dishes.OrderByDescending(d => d.OrderItems.Sum(oi => oi.Quantity)).Take(5).ToList();
            return View();
        }

        /// <summary>
        /// Отображает список кафе, опционально фильтруя их по типу
        /// </summary>
        /// <param name="type">Тип заведения</param>
        /// <returns></returns>
        [Route("cafe")]
        public ActionResult Cafes(CafeTypes type = CafeTypes.Все, long district = -1)
        {
            var cafes = DataContext.Cafes.ToList();

            if (district != -1)
            {
                cafes = cafes.Where(c => c.DistrictId == district).ToList();
            }
            
            if (type != CafeTypes.Все)
            {
                var filtred = new List<Cafe>();
                foreach (var cafe in cafes)
                {
                    var types =
                        (cafe.Types ?? "").Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(c => Convert.ToInt16(c))
                            .Select(c => (CafeTypes)c)
                            .ToList();

                    if (types.Contains(type))
                    {
                        filtred.Add(cafe);
                    }
                }
                return View(filtred);
            }
            return View(cafes);
        }

        /// <summary>
        /// Отображает список блюд в указанном кафе, фильтруя их по типу
        /// </summary>
        /// <param name="id"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        [Route("cafe/{id}/dishes")]
        public ActionResult Dishes(long id, long type = -1)
        {
            var cafe = DataContext.Cafes.FirstOrDefault(c => c.Id == id);
            if (cafe == null)
            {
                return RedirectToAction("Cafes");
            }

            var dishes = cafe.Dishes.ToList();
            ViewBag.cafe = cafe;
            ViewBag.type = type;
            if (type == -1)
            {
                return View(dishes);
            }
            else
            {
                return View(dishes.Where(d => d.TypeId == type).ToList());
            }
        }

        /// <summary>
        /// Отображает список всех блюд
        /// </summary>
        /// <param name="type">Тип блюд для фильтра</param>
        /// <returns></returns>
        [Route("dishes")]
        public ActionResult AllDishes(DishTypes type = DishTypes.Все)
        {
            var dishes = DataContext.Dishes.OrderByDescending(d => d.OrderItems.Count).ToList();
            if (type == DishTypes.Все)
            {
                return View(dishes);
            }
            else
            {
                var filtred = new List<Dishe>();
                foreach (var dish in dishes)
                {
                    var types = (dish.Types ?? "").Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(c => Convert.ToInt16(c))
                            .Select(c => (DishTypes)c)
                            .ToList();
                    if (types.Contains(type))
                    {
                        filtred.Add(dish);
                    }
                }
                return View(filtred);
            }
        }

        /// <summary>
        /// Отображает карточку указанного блюда
        /// </summary>
        /// <param name="id">Идентификатор блюда</param>
        /// <returns></returns>
        [Route("dish/{id}")]
        public ActionResult Dish(long id)
        {
            // Ищем блюдо
            var dish = DataContext.Dishes.FirstOrDefault(d => d.Id == id);
            if (dish == null || dish.Hidden)
            {
                return RedirectToAction("AllDishes");
            }

            return View(dish);
        }

        /// <summary>
        /// Обрабатывает добавление блюда к указанному заказу
        /// </summary>
        /// <param name="id">Идентификатор заказа</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-dish")]
        public ActionResult AddDish(long id)
        {
            // Ищем заказ
            var orderId = System.Web.HttpContext.Current.Request.ExtractOrderId();
            var dish = DataContext.Dishes.First(d => d.Id == id);
            Order order;
            if (orderId <= 0)
            {
                order = new Order()
                {
                    DateCreated = DateTime.Now,
                    Status = (short)OrderStatus.Creating
                };
                DataContext.Orders.InsertOnSubmit(order);
                DataContext.SubmitChanges();
                Response.Cookies.Add(new HttpCookie("currentOrder")
                {
                    Value = order.Id.ToString(),
                    Expires = DateTime.Now.AddDays(7)
                });
            }
            else
            {
                order = DataContext.Orders.FirstOrDefault(o => o.Id == orderId);
                if (order == null || order.Status != (short)OrderStatus.Creating)
                {
                    order = new Order()
                    {
                        DateCreated = DateTime.Now,
                        Status = (short)OrderStatus.Creating
                    };
                    DataContext.Orders.InsertOnSubmit(order);
                    DataContext.SubmitChanges();
                    Response.Cookies.Add(new HttpCookie("currentOrder")
                    {
                        Value = order.Id.ToString(),
                        Expires = DateTime.Now.AddDays(7)
                    });
                }
            }

            // Проверяем что все блюда в заказе из одного кафе то блюдо которое добавляет - оттуда же откуда все остальные блюда
            if (order.OrderItems.Count > 0 && order.OrderItems.Any(oi => oi.Dishe.CafeId != dish.CafeId))
            {
                return Json(
                            new { success = false, msg = "Нельзя в один заказ добавлять блюда из разных заведений" });
            }

            // Добавляем
            var orderItem = order.OrderItems.FirstOrDefault(o => o.DishId == id);
            if (orderItem == null)
            {
                orderItem = new OrderItem()
                {
                    DateCreated = DateTime.Now,
                    DishId = id,
                    Order = order,
                    Price = DataContext.Dishes.First(d => d.Id == id).Price,
                    Quantity = 1
                };
                order.OrderItems.Add(orderItem);
            }
            else
            {
                orderItem.Quantity = orderItem.Quantity + 1;
            }

            DataContext.SubmitChanges();

            return Json(new { success = true, count = System.Web.HttpContext.Current.Request.GetOrderedDishesCount(), sum = System.Web.HttpContext.Current.Request.GetOrderSum() });
        }

        /// <summary>
        /// Отображает страницу оформления заказа
        /// </summary>
        /// <returns></returns>
        [Route("checkout")]
        public ActionResult Checkout()
        {
            // Ищем заказ
            var orderId = System.Web.HttpContext.Current.Request.ExtractOrderId();
            var order = DataContext.Orders.FirstOrDefault(o => o.Id == orderId);
            if (order == null || order.Status != (short)OrderStatus.Creating || order.OrderItems.Count == 0)
            {
                return View("NoOrder");
            }

            return View(order);
        }

        /// <summary>
        /// Изменяет позицию в указанном элементе заказа
        /// </summary>
        /// <param name="id">Идентификатор элемента</param>
        /// <param name="quantity">Новое значение</param>
        /// <returns></returns>
        [Route("change-quantity")]
        public ActionResult ChangeQuantity(long id, int quantity)
        {
            try
            {
                var orderItem = DataContext.OrderItems.FirstOrDefault(oi => oi.Id == id);
                if (orderItem == null)
                {
                    throw new Exception("Объект не найден");
                }
                if (quantity <= 0)
                {
                    quantity = 1;
                }
                orderItem.Quantity = quantity;
                DataContext.SubmitChanges();

                return Json(new { success = true });
            }
            catch (Exception e)
            {
                return Json(new { success = false, msg = e.Message });
            }
        }
        /// <summary>
        /// Удаляет позицию из заказа
        /// </summary>
        /// <param name="id">Идентификатор элемента</param>
        /// <returns></returns>
        [Route("delete-dish")]
        public ActionResult DeleteDish(long id)
        {
            try
            {
                var orderItem = DataContext.OrderItems.FirstOrDefault(oi => oi.Id == id);
                if (orderItem == null)
                {
                    throw new Exception("Объект не найден");
                }
                DataContext.OrderItems.DeleteOnSubmit(orderItem);
                DataContext.SubmitChanges();

                return Json(new { success = true });
            }
            catch (Exception e)
            {
                return Json(new { success = false, msg = e.Message });
            }
        }

        /// <summary>
        /// Обрабатывает оформление заказа
        /// </summary>
        /// <param name="name">Имя</param>
        /// <param name="phone">Телефон</param>
        /// <param name="email">Email</param>
        /// <param name="address">Адрес доставки</param>
        /// <param name="comments">Комментарии</param>
        /// <returns></returns>
        [Route("do-checkout")]
        [HttpPost]
        public ActionResult DoCheckout(string name, string phone, string email, string address, string comments)
        {
            // Ищем заказ
            var orderId = System.Web.HttpContext.Current.Request.ExtractOrderId();
            var order = DataContext.Orders.FirstOrDefault(o => o.Id == orderId);
            if (order == null || order.Status != (short)OrderStatus.Creating || order.OrderItems.Count == 0)
            {
                return View("NoOrder");
            }

            // Проверяем что у нас есть заказы
            var sum = order.OrderItems.Sum(oi => oi.Quantity);
            if (sum <= 0)
            {
                return RedirectToAction("Checkout");
            }

            // Оформляем
            order.ContactName = name + ", Email: " + email;
            order.ContactPhone = phone;
            order.DeliveryAddress = address + ", комментарии: " + comments;
            order.Status = (short)OrderStatus.Checkout;
            order.DateCreated = DateTime.Now;
            DataContext.SubmitChanges();

            // Очищаем куку заказа
            Response.Cookies.Add(new HttpCookie("currentOrder")
            {
                Expires = DateTime.Now.AddDays(-1)
            });

            // Формируем письмо
            var target = ConfigurationManager.AppSettings["OrderEmail"];
            var uniSenderApiKey = ConfigurationManager.AppSettings["UniSenderApiKey"];
            var sb = new StringBuilder();
            sb.AppendFormat(
                "<p>Поступил новый заказ <b>№{0}</b> на сайте Единой службы доставки <a href='http://дсплюс.рф'>Доставка Плюс</a> от пользователя {1}, тел: {2}, на адрес {3}</p>", order.Id, name, phone, address);
            sb.AppendFormat(
                "<table border='1' style='border: 1px solid black'><thead><tr><th>Артикул</th><th>Блюдо</th><th>Кафе</th><th>Количество</th><th>Стоимость</th></tr></thead><tbody>");
            foreach (var orderItem in order.OrderItems)
            {
                sb.AppendFormat("<tr><td>{4}</td><td>{0}</td><td>{1}</td><td>{2}</td><td>{3:c}</td></tr>", orderItem.Dishe.Title, orderItem.Dishe.Cafe.Title, orderItem.Quantity, orderItem.Price * orderItem.Quantity, orderItem.Dishe.Energy);
            }
            sb.AppendFormat("</tbody></table>");
            sb.AppendFormat("<p><a href='http://дсплюс.рф/ControlPanel/ManageOrders/Edit/{0}'>Ссылка на заказ</a></p>", order.Id);
            // Отправляем письмо
            var client = new WebClient();
            var request = "http://api.unisender.com/ru/api/sendEmail?format=json";
            var requestParams = new NameValueCollection
            {
                {"api_key", uniSenderApiKey},
                {"email", target},
                {"sender_name", "Система Доставка+"},
                {"sender_email", "mailing.nprdv@gmail.com"},
                {"subject", "Новый заказ на сайте ДоставкаПлюс"},
                {"body", sb.ToString()},
                {"list_id", "2959162"},
                {"lang", "ru"}
            };

            // Пытаемся отправить
            try
            {
                var response = Encoding.UTF8.GetString(client.UploadValues(request, requestParams));
                if (response.Contains("\"email_id\""))
                {
                    // Все ок
                }
                else
                {
                    // НЕ ОК
                }
            }
            catch (Exception e)
            {
                // НЕ ОК
            }

            // Отправляем смс уведомление
            // Корневой объект отправки
            var rootObject = new JObject(new JProperty("apikey", new JValue(System.Configuration.ConfigurationManager.AppSettings["SMSAPIKey"])));

            // Массив, содержащий отправляемые сообщения
            var sendArray = new JArray();

            var sendObject = new JObject(
                    new JProperty("id", new JValue(Guid.NewGuid())),
                    new JProperty("from", new JValue("softgears")),
                    new JProperty("to", new JValue(ConfigurationManager.AppSettings["SMSFeedback"])),
                    new JProperty("text", new JValue(String.Format("Оформлен новый заказ №{0} от {1} - {2}", order.Id, name, phone))));

            sendArray.Add(sendObject);
            rootObject.Add(new JProperty("send", sendArray));

            // Отправляем
            HttpWebResponse smsResponse = null;
            try
            {
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(String.Format("http://smspilot.ru/api2.php?json={0}", HttpUtility.UrlEncode(rootObject.ToString())));
                smsResponse = (HttpWebResponse)webRequest.GetResponse();

                // Обрабатываем результат
                bool sendSuccess = false;
                var responseStream = smsResponse.GetResponseStream();
                if (responseStream != null)
                {
                    // Анализируем ответ
                    var json = new StreamReader(responseStream).ReadToEnd();
                    if (json.Contains("\"send\""))
                    {
                        // NOTE: все ок
                    }
                }
            }
            catch (Exception e)
            {
                // Не ок
            }

            return View(order);
        }

        /// <summary>
        /// Отображает указанную новость
        /// </summary>
        /// <param name="id">Идентификатор новости</param>
        /// <returns></returns>
        [Route("article/{id}")]
        public ActionResult ViewArticle(long id)
        {
            var article = DataContext.Articles.FirstOrDefault(a => a.Id == id);
            if (article == null)
            {
                return RedirectToAction("Articles");
            }

            article.Views += 1;
            DataContext.SubmitChanges();

            return View(article);
        }

        /// <summary>
        /// Отображает список всех новостей
        /// </summary>
        /// <returns></returns>
        [Route("articles")]
        public ActionResult Articles(int page = 0)
        {
            var all = DataContext.Articles.Where(a => a.PublicationDate <= DateTime.Now)
                    .OrderByDescending(a => a.PublicationDate).ToList();

            ViewBag.total = all.Count;
            ViewBag.page = page;

            return View(all.Skip(page * 10).Take(10).ToList());
        }

        /// <summary>
        /// Отображает страницу с видео
        /// </summary>
        /// <returns></returns>
        [Route("video")]
        public ActionResult Video()
        {
            return View();
        }

        /// <summary>
        /// Отображает страницу с информацией о доставке
        /// </summary>
        /// <returns></returns>
        [Route("delivery")]
        public ActionResult Delivery()
        {
            ViewBag.deliveryInfo = DataContext.Articles.Where(i => i.IsAboutDelivery == true).FirstOrDefault();
            return View();
        }

        /// <summary>
        /// Отображает страницу контактов
        /// </summary>
        /// <returns></returns>
        [Route("contacts")]
        public ActionResult Contacts()
        {
            return View();
        }

        /// <summary>
        /// Обрабатывает поиск блюд
        /// </summary>
        /// <param name="q">Поисковый запрос</param>
        /// <returns></returns>
        [Route("search")]
        public ActionResult Search(string q)
        {
            if (String.IsNullOrEmpty(q))
            {
                return RedirectToAction("Index");
            }

            // Ищем
            var items =
                DataContext.Dishes.Where(d => d.Title.ToLower().Contains(q.ToLower()))
                    .OrderByDescending(d => d.OrderItems.Sum(oi => oi.Quantity))
                    .ToList();

            // Отдаем
            return View(items);
        }
    }
}
